MybatisPlus 主键为自增id时根据特定多字段判断是否在数据库内存在该条记录,存在则更新、不存在则插入 您所在的位置:网站首页 mybatisplus 联合主键 MybatisPlus 主键为自增id时根据特定多字段判断是否在数据库内存在该条记录,存在则更新、不存在则插入

MybatisPlus 主键为自增id时根据特定多字段判断是否在数据库内存在该条记录,存在则更新、不存在则插入

2023-06-18 00:07| 来源: 网络整理| 查看: 265

目录

需求

单主键校验

非主键多字段校验

多主键校验

需求

        主键字段使用了自增id做了优化,但是需求需要依赖两个联合唯一的字段校验该条记录是否存在,如果存在则执行更新操作,不存在则执行插入操作。

单主键校验

        一开始打算手写sql,使用SelcetKey + foreach 先根据两个字段查出对应的id,如果id不存在则插入,否则更新,但是底层是单条多次的sql提交,很影响性能。

        后来发现的ServiceImpl类下有一个saveOrUpdateBatch方法:

@Transactional( rollbackFor = {Exception.class} ) public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass); Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]); String keyProperty = tableInfo.getKeyProperty(); Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]); return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> { Object idVal = ReflectionKit.getFieldValue(entity, keyProperty); return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_BY_ID), entity)); }, (sqlSession, entity) -> { ParamMap param = new ParamMap(); param.put("et", entity); sqlSession.update(this.getSqlStatement(SqlMethod.UPDATE_BY_ID), param); }); }

        看起来已经帮我们封装好了,但是它针对的是单主键的校验,我们的主键是数据库自增的,需要校验的是非主键字段,不太适用。

非主键多字段校验(主要)

            最终优化了一下代码,直接在Service实现里调用即可:

public boolean saveOrUpdateBatch2(List list, int batchSize) { return SqlHelper.executeBatch(entityClass, log, list, batchSize, (sqlSession, entity) -> { HashMap param = new HashMap(); LambdaQueryWrapper eq = Wrappers.lambdaQuery() .eq(XXXModel::getXXX1, entity.getXXX1()) .eq(XXXModel::getXXX2, entity.getXXX2()); param.put("ew", eq); XXXModelmodel = sqlSession.selectOne(getSqlStatement(SqlMethod.SELECT_ONE), param); if (model == null) { sqlSession.insert(getSqlStatement(SqlMethod.INSERT_ONE), entity); } else { entity.setId(model.getId()); param.put("et",entity); sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param); } }); }

        先查一次数据,判断是否存在,不存在则插入,存在则根据查到的id主键更新。

        批量操作时,底层会把sql先缓存在SqlSession内,调用sqlSession.flushStatements()时才会把数据发到数据库执行:

public static boolean executeBatch(Class entityClass, Log log, Collection list, int batchSize, BiConsumer consumer) { Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]); return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> { int size = list.size(); int i = 1; for(Iterator var6 = list.iterator(); var6.hasNext(); ++i) { E element = var6.next(); consumer.accept(sqlSession, element); if (i % batchSize == 0 || i == size) { //满足一个batchSize 或 传入大小不足一个batchSize时 批处理提交 sqlSession.flushStatements(); } } }); }

        需要注意的是,如果不使用SqlSession而是直接使用baseMapper来查会报空指针异常,日志也没有打印堆栈信息,异常在底层被捕获了又抛出。(个人猜测跟SqlSession的底层封装有关,一个会话内的sql必须要依赖同一个SqlSession执行)

多主键校验

        联合主键的批量插入or更新其实有MppBaseMapper针对原生的BaseMapper做了实现,如果表结构为联合主键,可以分别继承MppBaseMapper、IMppService直接调用即可。具体代码为MppServiceImpl:saveOrUpdateBatchByMultiId():

@Transactional( rollbackFor = {Exception.class} ) public boolean saveOrUpdateBatchByMultiId(Collection entityList, int batchSize) { TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass); Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]); //这里面其实是获取实体类中使用了MppMultiId注解的字段映射为Map 这个字段是Mpp用来用于标识多个主键的 Map idMap = this.checkIdCol(this.entityClass, tableInfo); Assert.notEmpty(idMap, "entity {} not contain MppMultiId anno", new Object[]{this.entityClass.getName()}); return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> { boolean updateFlag = true; Iterator var6 = idMap.keySet().iterator(); while(var6.hasNext()) { String attr = (String)var6.next(); //校验主键是否为空 为空则不更新 if (StringUtils.checkValNull(attr)) { updateFlag = false; break; } } //走到此处 说明主键均不为空 接着查数据库判断该记录是否存在 if (updateFlag) { Object obj = this.selectByMultiId(entity); if (Objects.isNull(obj)) { updateFlag = false; } } //更新或插入 if (updateFlag) { ParamMap param = new ParamMap(); param.put("et", entity); sqlSession.update(tableInfo.getSqlStatement("updateByMultiId"), param); } else { sqlSession.insert(tableInfo.getSqlStatement(SqlMethod.INSERT_ONE.getMethod()), entity); } }); }



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有